import * as lodash from "lodash-es";
import { Ref } from "vue";
import MQWorker from "./worker?worker";
import { NormalMessageType, WebWorkerStartBase } from "../../../ts/webworker";
import { MQWorkerMessageType } from "./common";

type MQHandler = (topic: string, message: any) => void;

export interface MQWebSocketConfig {
  // websocket 服务路径
  url: string;
}

export function NewMQWebSocketConfig(
  cfg: Partial<MQWebSocketConfig>
): MQWebSocketConfig {
  return {
    url: "ws://127.0.0.1",
    ...cfg,
  };
}

interface MQWebSocketConfigInternal {
  // websocket 服务路径
  url: string;

  // 外部绑定的 Connect 属性
  isConnected: Ref<boolean> | undefined;
}

export class MQWebSocket extends WebWorkerStartBase {
  // topic 相关处理函数
  private mqHandlers: Map<string, MQHandler>;
  private _dispose = false;
  private timer: NodeJS.Timeout | undefined;

  constructor(cfg: MQWebSocketConfigInternal) {
    super();
    this.name = "MQ";
    this.cfg = cfg;
    this.mqHandlers = new Map();
    this.startWorker(new MQWorker());
  }

  init() {
    super.init();
    const start = this.getHandler(NormalMessageType.STARTED)!;
    this.addHandler(NormalMessageType.STARTED, () => {
      this.logger("执行 启动handler");
      this.logger(this);

      this.postMessage({
        type: NormalMessageType.CFG,
        data: {
          url: this.cfg.url,
        },
      });

      this.postMessage({
        type: MQWorkerMessageType.OPEN,
        data: null,
      });

      start(0, 0);
    });

    this.addHandler(MQWorkerMessageType.MESSAGE, (type, data) => {
      this.messageHandler(type, data);
    });
    this.addHandler(MQWorkerMessageType.CLOSE, (type, data) => {
      this.closeHandler();
    });
    this.addHandler(MQWorkerMessageType.OPEN, (type, data) => {
      this.openHandler();
    });
  }

  private closeHandler() {
    this.changeIsConnected(false);
    this.logger(`连接已关闭`);
  }

  private changeIsConnected(value: boolean) {
    if (this.cfg.isConnected) {
      this.cfg.isConnected.value = value;
    }
  }

  private openHandler() {
    this.changeIsConnected(true);
    this.logger(`连接已开启`);
  }

  private messageHandler(type: number | string, data: any) {
    const topic = data.topic;
    const msg = data.msg;
    this.mqHandlers.forEach((value, key) => {
      if (lodash.startsWith(topic, key)) {
        value(topic, msg);
      }
    });
  }

  public sub(topics: string): boolean {
    this.postMessage({
      type: MQWorkerMessageType.SUB,
      data: {
        topics: topics,
      },
    });
    return true;
  }

  public async pub(topic: string, message: string) {
    this.postMessage({
      type: MQWorkerMessageType.PUB,
      data: {
        topic: topic,
        message: message,
      },
    });
  }

  public async pubJson(topic: string, message: any) {
    this.pub(topic, JSON.stringify(message));
  }

  /**
   * 销毁 ws
   * 在内部已调用,不用自己调用此函数
   */
  dispose() {
    this._dispose = true;
    this.worker && this.worker.terminate();
    if (this.timer) {
      clearTimeout(this.timer);
    }
  }

  public addMQHandler(topic: string, func: MQHandler) {
    this.logger(`增加处理函数`, topic);
    this.mqHandlers.set(topic, func);
  }

  public removeMQHandler(topic: string) {
    this.logger(`删除处理函数`, topic);
    this.mqHandlers.delete(topic);
  }
}
